#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         CheckBox.py
#
# Copyright:    Copyright (c) 2004, Faulkner Technologies
#
# Author:       Tom Cameron, Brian Oliver
#
# Description:  A CheckBox is a primitive Component
#               to represent simple true/false/undefined information
#               in an assessment.
#
#               Originally this component was based on the
#               BooleanComponent in pre 1.0 versions of the
#               KnowledgeEngine. However as this component now
#               supports the additional 'undefined' state, it is
#               no longer a strickly 'boolean' component.
#
# See Also:     Component, Model, Section
#####################################################################

#####################################################################
## Knowledge Engine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.Core import *
from Products.KnowledgeEngine.Component import Component, ComponentInfo
from Products.KnowledgeEngine.Assessible import Assessible
from Products.KnowledgeEngine.AssessmentFilter import AssessmentFilter
from Products.KnowledgeEngine.AssessmentComponentState import AssessmentComponentState
from Products.KnowledgeEngine.AssessmentComponentValueTypes import *
from Products.KnowledgeEngine.Exportable import Exportable
from Products.KnowledgeEngine.KERLExtensions import KERLExtensions
from Products.KnowledgeEngine.KERLProcessor import *
from Products.KnowledgeEngine.KERFProcessor import *
from Products.KnowledgeEngine.Scorable import *
from Products.KnowledgeEngine.PropertyDefinition import *
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *
from Products.KnowledgeEngine.Graphing.Graphable import *
from Products.KnowledgeEngine.Graphing.Datum import *
from Products.KnowledgeEngine.User import User
from Products.KnowledgeEngine.Caching import RequestCache
from Products.KnowledgeEngine.KERLProcessor import InvalidKerlOperator

#####################################################################
## Zope Library Imports
from Globals import DTMLFile
from App.ImageFile import ImageFile

#####################################################################
## Zope CMF Library Imports
from Products.CMFCore.PortalContent import PortalContent
from Products.CMFCore.ActionInformation import ActionInformation
from Products.CMFCore import permissions
from Products.CMFCore.permissions import ModifyPortalContent

#####################################################################
## Python Library Imports
import types

#####################################################################
## CheckBoxInfo Class Definition
class CheckBoxInfo(ComponentInfo, ScorableInfo):
    """
        Defines the class info methods, defining information about
        the class without needing an instance of the class
    """

    #---------------------------------------------------------------#

    def getClassName(self):
        """
            Return the class name
        """

        return 'CheckBox'

    #---------------------------------------------------------------#

    def getDisplayName(self):
        """
            Return a friendly name for the class instances
            (this is used for displaying in lists etc)
        """

        return "Choice Question"

    #---------------------------------------------------------------#

    def getIdentityType(self):
        """
            Return the identity type.
        """

        return "chk"

    #---------------------------------------------------------------#

    def getClassIcon(self):
        """
            Return the appropriate icon file for the class.
        """

        return ImageFile('skins/CheckBox_icon.gif', globals())

    #---------------------------------------------------------------#

    def isInstanceOf(self, className):
        """
            Returns if the class is an instance of the specified
            className, or implements the interface specified
            by the className
        """

        return className in ('Checkbox', 'Assessible', 'Exportable') or ScorableInfo.isInstanceOf(self,className) or ComponentInfo.isInstanceOf(self, className)

    #---------------------------------------------------------------#

    def onConfigureProperties(self):
        """
            Automatically called by the Knowledge Engine once
            the class has been loaded.  Use this method to register
            class specific properties using the PropertyReflection interface.

            If this class is sub-classed, a call must be made to
            the super-class to ensure super-class properties are
            correctly registered

            NOTE: This method is called before ClassInfo.onAfterStartup()
        """

        #initialise the super-class properties for reflection
        ComponentInfo.onConfigureProperties(self)
        ScorableInfo.onConfigureProperties(self)

        #add the 'reportContentWhenSelected' property
        self.addPropertyDefinition(PropertyDefinition(identity="reportContentWhenSelected", displayName="Report Content (when Yes is selected)", description="Text to be displayed in a report for this component when it is true/on/yes.", defaultValue="", propertyType=pt_STRING, propertyFormat=pf_HTML, propertyStructure=ps_ATOMIC))

        #add the 'reportContentWhenUnselected' property
        self.addPropertyDefinition(PropertyDefinition(identity="reportContentWhenUnselected", displayName="Report Content (when No is selected)", description="Text to be displayed in a report for this component when it is false/off/no.", defaultValue="", propertyType=pt_STRING, propertyFormat=pf_HTML, propertyStructure=ps_ATOMIC))

        #add the 'reportContentWhenUndefined' property
        self.addPropertyDefinition(PropertyDefinition(identity="reportContentWhenUndefined", displayName="Report Content (when Nothing is selected)", description="Text to be displayed in a report for this component when no selection has been made", defaultValue="", propertyType=pt_STRING, propertyFormat=pf_HTML, propertyStructure=ps_ATOMIC))

        #add the 'defaultValue' property
        self.addPropertyDefinition(PropertyDefinition(identity="defaultValue", displayName="Default Value", description="The value used for this component i). in newly created assessments, ii). when added to a model and assessments already exist in that model, or iii). when not changed by a user in an assessment", propertyType=pt_INTEGER, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesMapping=[("Yes", true),("No", false),("(undefined)",undefined)], defaultValue=undefined))

        #add the 'displayFormat' property
        self.addPropertyDefinition(PropertyDefinition(identity="displayFormat", displayName="Display As", description="What values should be displayed?", propertyType=pt_STRING, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesList=["Yes/No","True/False","On/Off"], defaultValue="Yes/No"))

        #add the 'scoreTrue' property
        self.addPropertyDefinition(PropertyDefinition(identity="scoreTrue", displayName="Score (when Yes is selected)", description="The score for the component when Selected/On/Yes/Checked in an assessment", defaultValue=1.0, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC))

        #add the 'scoreFalse' property
        self.addPropertyDefinition(PropertyDefinition(identity="scoreFalse", displayName="Score (when No is selected)", description="The score for the component when Unelected/Off/No/Unchecked in an assessment", defaultValue=0.0, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC))

        #add the 'scoreFalse' property
        self.addPropertyDefinition(PropertyDefinition(identity="scoreUndefined", displayName="Score (when Nothing is selected)", description="The score for the component when no selection has been made in an assessment", defaultValue=0.0, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC))

    #---------------------------------------------------------------#

#####################################################################
## CheckBox Class Definition
class CheckBox(Component, Assessible, KERLExtensions, Scorable, Exportable):
    """
        Defines a a simple component to represent a boolean selection
        in an assessment
    """

    #---------------------------------------------------------------#

    #TRANSIENT: a ClassInfo implementation instance to provide info about this class
    _CLASSINFO = CheckBoxInfo()

    #---------------------------------------------------------------#

    # Default Values for backward compatibility
    displayList = ["Yes/No","True/False","On/Off"]
    displayFormat = "Yes/No"
    scoreTrue = 1.0
    scoreFalse = 0.0
    scoreUndefined = 0.0

    #---------------------------------------------------------------#

    # DTML Methods
    index_html = DTMLFile('dtml/index_html', globals())
    simplereport_html = DTMLFile('dtml/simplereport_html', globals())
    scoredreport_html = DTMLFile('dtml/scoredreport_html', globals())
    scored360report_html = DTMLFile('dtml/scored360report_html', globals())
    csv360report_html = DTMLFile('dtml/csv360report_html', globals())
    groupedreport_html = DTMLFile('dtml/groupedreport_html', globals())

    #---------------------------------------------------------------#

    def __init__(self, id, identity):
        "Constructor for the CheckBox"

        Component.__init__(self, id, identity)

    #---------------------------------------------------------------#

    def onAfterInstanciation(self):
        """
            Handle Knowledge Engine specific actions after this object
            has been loaded into memory.

            This is useful for performing backwards compatibility
        """

        #perform Component.onAfterInstanciation processing
        Component.onAfterInstanciation(self)

        #as we no longer support the 'checkbox' type of display, we need to convert it to a Yes/No type
        if self.getDisplayFormat() == 'CheckBox':
            self.setDisplayFormat("Yes/No")

        ###print "DEBUG: CheckBox.onAfterInstanciation: Completed"

    #---------------------------------------------------------------#

    def getDisplayFormat(self):
        """
            Return the display format of this object
        """

        return self.displayFormat

    #---------------------------------------------------------------#

    def setDisplayFormat(self, displayFormat):
        """
            Set the display format of this object
        """

        self.displayFormat = displayFormat

    #---------------------------------------------------------------#

    def onAfterIdentityChange(self, identityMappings):
        """
            Handle Knowledge Engine specific actions after the
            identity of this object has changed.

            The identityMappings dictionary holds
            mappings from oldIdentities -> newIdentities
            (including this object)

        """

        #perform default identity changes
        Component.onAfterIdentityChange(self, identityMappings)

        #resolve report KERFs
        self.setReportContentWhenSelected(updateKERF(self.getReportContentWhenSelected(), identityMappings))
        self.setReportContentWhenUnselected(updateKERF(self.getReportContentWhenUnselected(), identityMappings))
        self.setReportContentWhenUndefined(updateKERF(self.getReportContentWhenUndefined(), identityMappings))

    #---------------------------------------------------------------#

    def getReportContentForValue(self, value):
        """ Returns the report content for the specified value on this component """

        if value == 1:
            return self.getReportContentWhenSelected()
        elif value == 0:
            return self.getReportContentWhenUnselected()
        else:
            return self.getReportContentWhenUndefined()

    #---------------------------------------------------------------#

    def getReportContentWhenSelected(self):
        """
            Returns the Report Content for this component
            when Yes is selected in an assessment
        """

        return self.reportContentWhenSelected

    #---------------------------------------------------------------#

    def setReportContentWhenSelected(self, reportContentWhenSelected):
        """
            Sets the Report Content for this component
            when Yes is selected in an assessment
        """

        self.reportContentWhenSelected = reportContentWhenSelected

    #---------------------------------------------------------------#

    def getReportContentWhenUnselected(self):
        """
            Returns the Report Content for this component
            when No is selected in an assessment
        """

        return self.reportContentWhenUnselected

    #---------------------------------------------------------------#

    def setReportContentWhenUnselected(self, reportContentWhenUnselected):
        """
            Sets the Report Content for this component
            when No is selected in an assessment
        """

        self.reportContentWhenUnselected = reportContentWhenUnselected

    #---------------------------------------------------------------#

    def getReportContentWhenUndefined(self):
        """
            Returns the Report Content for this component
            when nothing is selected in an assessment
        """

        return self.reportContentWhenUndefined

    #---------------------------------------------------------------#

    def setReportContentWhenUndefined(self, reportContentWhenUndefined):
        """
            Sets the Report Content for this component
            when nothing is selected in an assessment
        """

        self.reportContentWhenUndefined = reportContentWhenUndefined

    #---------------------------------------------------------------#

    def getDefaultValue(self):
        """
            Returns the default value of the component
            for new assessments; true = 1, false = 0 or undefined = -1
        """

        return self.defaultValue

    #---------------------------------------------------------------#

    def setDefaultValue(self, defaultValue):
        """
            Sets the default value of the component
            for new assessments; true = 1, false = 0 or undefined = -1
        """

        self.defaultValue = defaultValue

    #---------------------------------------------------------------#

    def getTypedAssessmentValue(self, formValue):
        """
            Returns the correctly typed python value for the
            specified HTTP form value

            Called By: AssesssmentCache.setState
        """

        #ensure the assessment value is a tristate
        if type(formValue) is types.StringType:
            if formValue == 'on' or formValue == 'checked' or formValue == 'selected' or formValue == 'true':
                return true
            elif formValue == 'off' or formValue == 'unchecked' or formValue == 'unselected' or formValue == 'false':
                return false
            else:
                return undefined

        else:
            return formValue

    #---------------------------------------------------------------#

    def getComponentProperty(self, identity, propertyName, assessment = None):
        """
            Returns the value of the specified property, given the
            identity of the component (which may be used to lookup states) and
            an assessment.

            RETURNS: None if the property doesnt exist
        """

        value = assessment.getComponentState(identity).getValue()

        if propertyName == "value":
            if value == true:
                return "Yes"
            elif value == false:
                return "No"
            else:
                return "Undefined"
        else:
            return Component.getComponentProperty(self, identity, propertyName, assessment)

    #---------------------------------------------------------------#

    def getScore(self, assessment):
        """
            Evaluates the unweighted score of the component..

            Typically called by Scorable.getScore() to retrieve
            score. Or Scorable.getScore()*Scorable.getWeighting()

            NOTE: Must return a real number
        """

        #get the identity
        identity = self.getIdentity()

        #get the stored state
        state = assessment.getComponentState(identity).getValue()

        #evaluate and return the score
        if state == true:
            return self.scoreTrue
        elif state == false:
            return self.scoreFalse
        else:
            return self.scoreUndefined

    #---------------------------------------------------------------#

    def getMaxScore(self):
        """
            Evaluates the maximum potential score
        """

        #evaluate and return the score
        return max([self.scoreTrue, self.scoreFalse, self.scoreUndefined])

    #---------------------------------------------------------------#
    # BEGIN: Assessible Implementation                              #
    #---------------------------------------------------------------#

    def getAssessmentValueType(self):
        """
            ABSTRACT: Returns the type of the value that is to be stored
            for this component when it's assessment state is persisted.

            NOTE 1: See AssessmentComponentValueTypes for a list of defined contants
            NOTE 2: This method MUST be overriden in the implementing
            class to specify the correct type for value persistence

            RETURN TYPE: String
        """

        #checkbox assessment values are tristates stored as booleans (booleans are actually numbers)
        return st_BOOLEAN

    #---------------------------------------------------------------#

    def getDefaultAssessmentState(self, assessment):
        """
            ABSTRACT: Constructs and returns a suitable 'default'
            AssessmentComponentState for the provided Assessment
            instance.

            NOTE: This method MUST be overriden in the implementing
            class to provide a suitable default value for the component

            RETURN TYPE: AssessmentComponentState
        """

        return AssessmentComponentState(assessment.getIdentity(), assessment.getModelIdentity(), self.getIdentity(), self.getAssessmentValueType(), self.getDefaultValue(), revision=assessment.getRevision())

    #---------------------------------------------------------------#

    def updateAssessmentState(self, assessment, formValue, skipMandatory=False):
        """
            ABSTRACT: Updates the specified assessment using
            the provided HTTP REQUEST formValue.

            NOTE: This method MUST be overriden in the implementing
            class to suitably update the component state
        """
        
        Component.updateAssessmentState( self, assessment, formValue, skipMandatory=skipMandatory )
        
        if self.getIsMandatory() and formValue == 'undefined':
            raise FieldRequiredException( "Field Required", component=self )

        #ensure the assessment value is a correctly typed tristate
        if type(formValue) is types.StringType:
            if formValue == 'on' or formValue == 'checked' or formValue == 'selected' or formValue == 'true':
                value = true
                searchValue = true
            elif formValue == 'off' or formValue == 'unchecked' or formValue == 'unselected' or formValue == 'false':
                value = false
                searchValue = false
            else:
                value = undefined
                searchValue = ""
        else:
            searchValue = value = formValue
            

        #get the current assessment state for the component from the assessment
        state = assessment.getComponentState(self.getIdentity())

        print "SETTING CHECKBOX %s = %s" % ( self.getIdentity(), `value` )

        #update the current state
        state.setValue(value)
        state.setIsModified( true )
        
        # If a searchIndex is defined, add that info to the component state
        searchIndex = getattr(self, 'searchIndex', False)
        if searchIndex:
            state.setSearchIndex(searchIndex)
            state.setSearchValue(searchValue)
            #if value == true:
                #state.setSearchIndex(searchIndex)
                #state.setSearchValue(value)
            #else:
                #state.setSearchIndex(searchIndex)
                #state.setSearchValue(va)            
        

        #update the assessment
        assessment.setIsModified(true)

    #---------------------------------------------------------------#
    # END: Assessible Implementation                                #
    #---------------------------------------------------------------#

    #---------------------------------------------------------------#
    # BEGIN: KERLExtensions Implementation                          #
    #---------------------------------------------------------------#

    def compileKERLtoJavaScript(self, expression):
        """
            Returns a Python string that represents a JavaScript
            expression, which may be used to evaluate the status
            of the component class specific KERL expression.

            NOTE: this method is primarily used to produce
            JavaScript expressions that form the basis of the
            client-side showif technology.

            RETURN TYPE: String
        """

        #example: cond="['bool1','selected']" returns 'document.getElementById("bool1").value=="true"'
        #example: cond="['bool1','unselected']" returns 'document.getElementById("bool1").value=="false"'
        #example: cond="['bool1','undefined']" returns 'document.getElementById("bool1").value!="true" && document.getElementById("bool1").value!="false"'

        #get the identity
        identity = self.getIdentity()

        #get the value
        value = expression[1]

        if value == "selected":
            return "document.getElementById(\"" + identity + "\").value==\"true\""
        elif value == "unselected":
            return "document.getElementById(\"" + identity + "\").value==\"false\""
        elif value == "undefined":        
            return "(document.getElementById(\"" + identity + "\").value!=\"true\" && document.getElementById(\"" + identity + "\").value!=\"false\")"
        else:
            return Component.compileKERLtoJavaScript( self, expression )
            
            
            
            #raise InvalidKerlOperator( value )
            #return "(document.getElementById(\"" + identity + "\").value!=\"true\" && document.getElementById(\"" + identity + "\").value!=\"false\")"

    #---------------------------------------------------------------#

    def compileKERLtoEnglish(self, expression):
        """
            Returns a string representing an 'English' version
            of the component class specific KERL expression.

            NOTE: this method is primarily used to produce
            English descriptions of KERL expressions that may be 
            used to describe things like AssessmentFilters
            
            RETURN TYPE: String         
        """

        #example: cond="['bool1','selected']" returns '<title> is <display:true>'
        #example: cond="['bool1','unselected']" returns '<title> is <display:false>'
        #example: cond="['bool1','undefined']" returns '<title> is undefined'

        #get the identity
        identity = self.getIdentity()

        #get the value
        value = expression[1]
        trueTitle = self.getDisplayFormat().split('/')[0];
        falseTitle = self.getDisplayFormat().split('/')[1];

        if value == "selected":
            return "%s '%s' is %s" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), trueTitle)
        elif value == "unselected":
            return "%s '%s' is %s" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), falseTitle)
        elif value == "undefined":
            return "%s '%s' is undefined" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), )
        elif value == "notattempted":        
            return "%s '%s' is not attempted" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), )
        else:
            raise InvalidKerlOperator( value )
            

    #---------------------------------------------------------------#

    def evaluate(self, expression, assessment):
        """
            Evalutes the component class specific KERL expression
            using the provided assessment.

            NOTE: this method is primarily used to produce
            JavaScript expressions that form the basis of the
            client-side showif technology.

            RETURN TYPE: Boolean
        """

        #get the identity
        identity = self.getIdentity()

        #get the value
        value = expression[1]

        #get the stored state (and ensure it is a boolean)
        state = assessment.getComponentState(identity)

        #evaluate the expression
        if value == "selected":
            return state.getValue() == true
        elif value == "unselected":
            return state.getValue() == false
        elif value == "undefined":
            return state.getValue() == undefined
        else:
            raise InvalidKerlOperator( value )
            

    #---------------------------------------------------------------#

    def getDependencies(self, expression):
        """
            Returns a list of components that are required to
            evaluate the component class specific KERL expression.

            NOTE: Includes the specific component itself.

            RETURN TYPE: {Component} indexed by Component.getIdentity()
       """

        return {self.getIdentity():self}

    #---------------------------------------------------------------#

    def updateKERLIdentities(self, expression, identityMappings):
        """
            Returns the expression with the appropriate old identities
            (as identified by the identityMappings) replaced with
            new identities.
        """

        #get the component identity from the expression (first element)
        identity = expression[0]

        #is the component in the identityMappings?
        if identityMappings.has_key(identity):
            expression[0] = identityMappings[identity]

        return expression

    #---------------------------------------------------------------#
    # END: KERLExtensions Implementation                            #
    #---------------------------------------------------------------#

    def generateGraphableStatistics(self, baseAssessmentFilter = None, user = None, nrAssessments = None):
        """
            Generates a Graphable instance containing statistic
            information for this component - that may be graphed.
            
            The provided assessmentFilter is used as a basis for
            generating statistics information.  Setting this to
            None (the default) means all assessments are used.
            
            RETURN TYPE: Graphable
        """
       
        #ensure the baseAssessmentFilter is valid (not None)
        if baseAssessmentFilter is None:
            baseAssessmentFilter = self.getModel().getAllAssessmentsFilter()
        
        #determine the true and false titles
        trueTitle = self.getDisplayFormat().split('/')[0]
        falseTitle = self.getDisplayFormat().split('/')[1]
        
        #we need to use the assessment storage service to get the statistics
        assessmentStorageService = self.getModel().getAssessmentStorageService()

        #determine the number of assessments (if necessary)
        if nrAssessments is None:
            nrAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(baseAssessmentFilter, user)   
        
        #we need a Graphable for the results
        graphable = Graphable(self.getTitleOrId(), "The following chart outlines the selection statistics for the '%s' component in the %d current assessments." % (self.getTitleOrId(), nrAssessments), 0, nrAssessments)
        
        #create a datum for the number of times the component has been selected in the assessments
        filterTitle = "%s selections for %s" % (trueTitle, self.getTitleOrId())
        filterExpression = parseKERL("['%s', 'selected']" % self.getIdentity())
        assessmentFilter = AssessmentFilter(title=filterTitle, expression=simplifyKERL(['all', baseAssessmentFilter.getExpression(), filterExpression]), model=self.getModel(), assessmentScope=baseAssessmentFilter.getAssessmentScope())
        
        nrSelectedAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(assessmentFilter, user)
        datum = Datum(identity="selected", title="# %s." % trueTitle, value=nrSelectedAssessments, color="green", context={"ASSESSMENT_FILTER":assessmentFilter})
        graphable.addDatum(datum)

        #create a datum for the number of times the component has been unselected in the assessments
        filterTitle = "%s selections for %s" % (falseTitle, self.getTitleOrId())
        filterExpression = parseKERL("['%s', 'unselected']" % self.getIdentity())
        assessmentFilter = AssessmentFilter(title=filterTitle, expression=simplifyKERL(['all', baseAssessmentFilter.getExpression(), filterExpression]), model=self.getModel(), assessmentScope=baseAssessmentFilter.getAssessmentScope())
        
        nrUnselectedAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(assessmentFilter, user)
        datum = Datum(identity="unselected", title="# %s." % falseTitle, value=nrUnselectedAssessments, color="red", context={"ASSESSMENT_FILTER":assessmentFilter})
        graphable.addDatum(datum)

        undefinedKerl = [self.getIdentity(), 'notattempted']

        undefinedFilter = AssessmentFilter(title="Undefined Assessments", expression=simplifyKERL(['all', baseAssessmentFilter.getExpression(), undefinedKerl]), 
                                           model=self.getModel(), assessmentScope=baseAssessmentFilter.getAssessmentScope())

        #create a datum for the number of times the component has been unselected in the assessments
        datum = Datum(identity="undefined", title="# Undefined.", value=nrAssessments - nrSelectedAssessments - nrUnselectedAssessments, color="orange", 
                      context = {'ASSESSMENT_FILTER': undefinedFilter},
                      footnote="As it is possible for an end-user to avoid selecting either '%s' or '%s' for Choices, some assessments may have 'undefined' values." % (trueTitle, falseTitle))
                      
        graphable.addDatum(datum)
        
        return graphable

    #---------------------------------------------------------------#

    def listActions(self, info=None):
        """
            PLONE Support:

            Returns a tuple of ActionInformation instances
            specifying the available CMF Actions for the object

            overrides:

            (CMF Actions are different from Knowledge Engine Actions)
        """

        #add the super-class actions first
        lCMFActions = Component.listActions(self, info)

        #add the 'statistics' action
        lCMFActions = lCMFActions + (
                        ActionInformation(
                            id='statistics',
                            title='statistics',
                            description='Current Statistics',
                            category='object',
                            condition='',
                            permissions=(permissions.ListFolderContents,),
                            priority=1,
                            visible=1,
                            action='string:${object_url}/CheckBox_Statistics'
                        ),)
                        
        return lCMFActions

    #---------------------------------------------------------------#
    
    def hasReportContent( self ):
        """ Does this component have report content? """
        
        return ( Component.hasReportContent( self ) or 
                 self.getReportContentWhenSelected() or 
                 self.getReportContentWhenUndefined() or
                 self.getReportContentWhenUnselected() )
    
    
    
#####################################################################
## Class Initialisation

# Register Class Information with the Knowledge Engine
registerGenericObjectClass(CheckBox)

#####################################################################
